package com.example.service;

import com.example.entity.TomcatServer;
import com.example.repository.TomcatRepository;
import com.example.common.SSHUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

@Service
public class TomcatService {
    
    private static final Logger logger = LoggerFactory.getLogger(TomcatService.class);
    private static final int MAX_RETRY_COUNT = 2;
    private static final long RETRY_DELAY = 5000;
    
    @Autowired
    private TomcatRepository tomcatRepository;
    
    public Page<TomcatServer> findAll(Pageable pageable, String search) {
        if (!StringUtils.hasText(search)) {
            return tomcatRepository.findAll(pageable);
        }

        Specification<TomcatServer> spec = (root, query, cb) -> {
            String searchLike = "%" + search.toLowerCase() + "%";
            return cb.or(
                cb.like(cb.lower(root.get("serverName")), searchLike),
                cb.like(cb.lower(root.get("host")), searchLike),
                cb.like(cb.lower(root.get("port")), searchLike)
            );
        };
        
        return tomcatRepository.findAll(spec, pageable);
    }
    
    public List<TomcatServer> findAll() {
        return tomcatRepository.findAll();
    }
    
    public TomcatServer createServer(TomcatServer server) {
        logger.info("Creating new server: {}", server.getServerName());
        return tomcatRepository.save(server);
    }
    
    public void deleteServer(Long id) {
        logger.info("Deleting server with ID: {}", id);
        tomcatRepository.deleteById(id);
    }
    
    public void restartServer(Long id) {
        logger.info("Attempting to restart server with ID: {}", id);
        
        TomcatServer server = tomcatRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("Server not found with ID: " + id));
        
        retryOperation(() -> performRestart(server), "restart server " + server.getServerName());
    }
    
    private void performRestart(TomcatServer server) throws Exception {
        // 1. 查找并杀死现有进程
        String pidOutput = SSHUtil.executeCommand(server.getHost(), 
            String.format("netstat -nlp | grep :%s | grep LISTEN | awk \"{print \\$7}\" | cut -d\"/\" -f1", server.getPort()));
        String pid = pidOutput.trim();
        
        if (!pid.isEmpty()) {
            logger.info("Killing process: {} on server: {}", pid, server.getHost());
            SSHUtil.executeCommand(server.getHost(), "kill -9 " + pid);
            Thread.sleep(2000);
        }
        
        // 2. 启动Tomcat
        logger.info("Starting Tomcat at: {} on server: {}", server.getServerPath(), server.getHost());
        String startOutput = SSHUtil.executeCommand(server.getHost(), 
            "sh " + server.getServerPath() + "/bin/startup.sh");
        logger.info("Startup command output: {}", startOutput);
        
        // 3. 等待启动
        Thread.sleep(15000);
        
        // 4. 检查是否启动成功
        String checkResult = SSHUtil.executeCommand(server.getHost(), 
            "netstat -nlp | grep :" + server.getPort() + " | grep LISTEN");
        
        if (checkResult.trim().isEmpty()) {
            String logOutput = SSHUtil.executeCommand(server.getHost(), 
                "tail -n 500 " + server.getServerPath() + "/logs/catalina.out");
            logger.error("Tomcat logs: {}", logOutput);
            throw new RuntimeException("Server failed to start. Check catalina.out for details.");
        }
    }
    
    public TomcatServer updateServer(TomcatServer server) {
        logger.info("Updating server: {}", server.getServerName());
        return tomcatRepository.save(server);
    }

    public String getTomcatLogs(Long id, int lines) throws Exception {
        TomcatServer server = tomcatRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("Server not found with ID: " + id));
            
        return SSHUtil.executeCommand(server.getHost(), 
            String.format("tail -n %d %s/logs/catalina.out", lines, server.getServerPath()));
    }
    
    private void retryOperation(RunnableWithException operation, String operationName) {
        Exception lastException = null;
        for (int retryCount = 0; retryCount < MAX_RETRY_COUNT; retryCount++) {
            try {
                if (retryCount > 0) {
                    logger.info("Retry attempt {} for {}", retryCount, operationName);
                    Thread.sleep(RETRY_DELAY);
                }
                operation.run();
                return;
            } catch (Exception e) {
                lastException = e;
                logger.error("Attempt {} failed for {}", retryCount + 1, operationName, e);
                if (retryCount == MAX_RETRY_COUNT - 1) {
                    throw new RuntimeException(
                        String.format("Failed after %d attempts: %s", MAX_RETRY_COUNT, e.getMessage()), 
                        lastException);
                }
            }
        }
    }
    
    @FunctionalInterface
    private interface RunnableWithException {
        void run() throws Exception;
    }
} 